﻿using System.Diagnostics;
using CoreCalc;
using RayDen.Library.Core.Primitives;

namespace RayDen.Library.Data.Imaging
{
    public class ColorFactory
    {

        public static RgbSpectrum ToRgb(ref ISpectrum  spd)
        {
            var sp = (SampledSpectrum) spd;

            return ToRgb(ref sp);
        }

        public static RgbSpectrum ToRgb(ref SampledSpectrum spd)
        {
            return SSEToRgb(ref spd);
        }


        public static void ToRgb(ref SampledSpectrum spd, ref RgbSpectrum res)
        {
            SSEToRgb(ref spd, ref res);
        }
        public static RgbSpectrum SSEToRgb(ref SampledSpectrum spd)
        {
            var X = SampledSpectrum.X;
            var Y = SampledSpectrum.Y;
            var Z = SampledSpectrum.Z;
            var f_y = 1f/SampledSpectrum.yint;
            float[] rgb;
            float[] xyz = { f_y * SSE.Dot(ref spd, ref X), f_y * SSE.Dot(ref spd, ref Y), f_y * SSE.Dot(ref spd, ref Z)};
            SampledSpectrum.XYZToRGB(xyz, out rgb);
            return new RgbSpectrum(rgb);
        }

        public static void SSEToRgb(ref SampledSpectrum spd, ref RgbSpectrum res)
        {
            var X = SampledSpectrum.X;
            var Y = SampledSpectrum.Y;
            var Z = SampledSpectrum.Z;
            var f_y = 1f / SampledSpectrum.yint;
            SampledSpectrum.XYZToRGB(f_y * SSE.Dot(ref spd, ref X), f_y * SSE.Dot(ref spd, ref Y), f_y * SSE.Dot(ref spd, ref Z), out res.c1, out res.c2, out res.c3);
        }


        public static void SSEToRgb(RegularSPD spd, ref RgbSpectrum res)
        {
            var X = SampledSpectrum.CIE_X;
            var Y = SampledSpectrum.CIE_Y;
            var Z = SampledSpectrum.CIE_Z;
            var vals = spd.GetValues();
            var f_y = 1f / SampledSpectrum.yint;
            SampledSpectrum.XYZToRGB(f_y * SSE.VectorDot(vals, X, vals.Length),
                                     f_y * SSE.VectorDot(vals, Y, vals.Length),
                                     f_y * SSE.VectorDot(vals, Z, vals.Length),
                                     out res.c1, out res.c2, out res.c3);
        }


        public static RgbSpectrumInfo SSEToRgbInfo(ref SampledSpectrum spd)
        {
            var X = SampledSpectrum.X;
            var Y = SampledSpectrum.Y;
            var Z = SampledSpectrum.Z;
            var f_y = 1f / SampledSpectrum.yint;
            float[] rgb;
            float[] xyz = { f_y * SSE.Dot(ref spd, ref X), f_y * SSE.Dot(ref spd, ref Y), f_y * SSE.Dot(ref spd, ref Z) };
            SampledSpectrum.XYZToRGB(xyz, out rgb);
            return new RgbSpectrumInfo(rgb);
        }

        public static SampledSpectrum BaseFromRgb(float[] rgb, SpectrumType type = SpectrumType.Reflectance)
        {
            var r = new SampledSpectrum(0f);
            if (type == SpectrumType.Reflectance)
            {
                // Convert reflectance spectrum to RGB
                if (rgb[0] <= rgb[1] && rgb[0] <= rgb[2])
                {
                    // Compute reflectance _SampledSpectrum_ with _rgb[0]_ as minimum
                    //r += rgb[0] * rgbRefl2SpectWhite;
                    r.MAdd(ref SampledSpectrum.rgbRefl2SpectWhite, rgb[0]);
                    if (rgb[1] <= rgb[2])
                    {
                        r.MAdd(ref SampledSpectrum.rgbRefl2SpectCyan, (rgb[1] - rgb[0]));
                        r.MAdd(ref SampledSpectrum.rgbRefl2SpectBlue, (rgb[2] - rgb[1]));
                        //r += (rgb[1] - rgb[0]) * rgbRefl2SpectCyan;
                        //r += (rgb[2] - rgb[1]) * rgbRefl2SpectBlue;
                    }
                    else
                    {
                        //r += (rgb[2] - rgb[0]) * rgbRefl2SpectCyan;
                        //r += (rgb[1] - rgb[2]) * rgbRefl2SpectGreen;

                        r.MAdd(ref SampledSpectrum.rgbRefl2SpectCyan, (rgb[2] - rgb[0]));
                        r.MAdd(ref SampledSpectrum.rgbRefl2SpectGreen, (rgb[1] - rgb[2]));
                    }
                }
                else if (rgb[1] <= rgb[0] && rgb[1] <= rgb[2])
                {
                    // Compute reflectance _SampledSpectrum_ with _rgb[1]_ as minimum
                    //r += rgb[1] * rgbRefl2SpectWhite;
                    r.MAdd(ref SampledSpectrum.rgbRefl2SpectWhite, rgb[1]);

                    if (rgb[0] <= rgb[2])
                    {
                        //r += (rgb[0] - rgb[1]) * rgbRefl2SpectMagenta;
                        //r += (rgb[2] - rgb[0]) * rgbRefl2SpectBlue;

                        r.MAdd(ref  SampledSpectrum.rgbRefl2SpectMagenta, (rgb[0] - rgb[1]));
                        r.MAdd(ref  SampledSpectrum.rgbRefl2SpectBlue, (rgb[2] - rgb[0]));
                    }
                    else
                    {
                        //r += (rgb[2] - rgb[1]) * rgbRefl2SpectMagenta;
                        //r += (rgb[0] - rgb[2]) * rgbRefl2SpectRed;
                        r.MAdd(ref SampledSpectrum.rgbRefl2SpectMagenta, (rgb[2] - rgb[1]));
                        r.MAdd(ref SampledSpectrum.rgbRefl2SpectRed, (rgb[0] - rgb[2]));
                    }
                }
                else
                {
                    // Compute reflectance _SampledSpectrum_ with _rgb[2]_ as minimum
                    //r += rgb[2] * rgbRefl2SpectWhite;
                    r.MAdd(ref  SampledSpectrum.rgbRefl2SpectWhite, rgb[2]);

                    if (rgb[0] <= rgb[1])
                    {
                        //r += (rgb[0] - rgb[2]) * rgbRefl2SpectYellow;
                        //r += (rgb[1] - rgb[0]) * rgbRefl2SpectGreen;
                        r.MAdd(ref  SampledSpectrum.rgbRefl2SpectYellow, (rgb[0] - rgb[2]));
                        r.MAdd(ref  SampledSpectrum.rgbRefl2SpectGreen, (rgb[1] - rgb[0]));
                    }
                    else
                    {
                        //r += (rgb[1] - rgb[2]) * rgbRefl2SpectYellow;
                        //r += (rgb[0] - rgb[1]) * rgbRefl2SpectRed;

                        r.MAdd(ref SampledSpectrum.rgbRefl2SpectYellow, (rgb[1] - rgb[2]));
                        r.MAdd(ref SampledSpectrum.rgbRefl2SpectRed, (rgb[0] - rgb[1]));
                    }
                }
                r *= .94f;
            }
            else
            {
                // Convert illuminant spectrum to RGB
                if (rgb[0] <= rgb[1] && rgb[0] <= rgb[2])
                {
                    // Compute illuminant _SampledSpectrum_ with _rgb[0]_ as minimum
                    //r += rgb[0] * rgbIllum2SpectWhite;
                    r.MAdd(ref SampledSpectrum.rgbIllum2SpectWhite, rgb[0]);
                    if (rgb[1] <= rgb[2])
                    {
                        //r += (rgb[1] - rgb[0]) * rgbIllum2SpectCyan;
                        //r += (rgb[2] - rgb[1]) * rgbIllum2SpectBlue;
                        r.MAdd(ref SampledSpectrum.rgbIllum2SpectCyan, (rgb[1] - rgb[0]));
                        r.MAdd(ref SampledSpectrum.rgbIllum2SpectBlue, (rgb[2] - rgb[1]));

                    }
                    else
                    {
                        // r += (rgb[2] - rgb[0]) * rgbIllum2SpectCyan;
                        //r += (rgb[1] - rgb[2]) * rgbIllum2SpectGreen;

                        r.MAdd(ref SampledSpectrum.rgbIllum2SpectCyan, (rgb[2] - rgb[0]));
                        r.MAdd(ref SampledSpectrum.rgbIllum2SpectGreen, (rgb[1] - rgb[2]));
                    }
                }
                else if (rgb[1] <= rgb[0] && rgb[1] <= rgb[2])
                {
                    // Compute illuminant _SampledSpectrum_ with _rgb[1]_ as minimum
                    //r += rgb[1] * rgbIllum2SpectWhite;
                    r.MAdd(ref SampledSpectrum.rgbIllum2SpectWhite, rgb[1]);

                    if (rgb[0] <= rgb[2])
                    {
                        //r += (rgb[0] - rgb[1]) * rgbIllum2SpectMagenta;
                        //r += (rgb[2] - rgb[0]) * rgbIllum2SpectBlue;

                        r.MAdd(ref SampledSpectrum.rgbIllum2SpectMagenta, (rgb[0] - rgb[1]));
                        r.MAdd(ref SampledSpectrum.rgbIllum2SpectBlue, (rgb[2] - rgb[0]));
                    }
                    else
                    {
                        //r += (rgb[2] - rgb[1]) * rgbIllum2SpectMagenta;
                        //r += (rgb[0] - rgb[2]) * rgbIllum2SpectRed;

                        r.MAdd(ref SampledSpectrum.rgbIllum2SpectMagenta, (rgb[2] - rgb[1]));
                        r.MAdd(ref SampledSpectrum.rgbIllum2SpectRed, (rgb[0] - rgb[2]));
                    }
                }
                else
                {
                    // Compute illuminant _SampledSpectrum_ with _rgb[2]_ as minimum
                    //r += rgb[2] * rgbIllum2SpectWhite;
                    r.MAdd(ref SampledSpectrum.rgbIllum2SpectWhite, rgb[2]);

                    if (rgb[0] <= rgb[1])
                    {
                        //r += (rgb[0] - rgb[2]) * rgbIllum2SpectYellow;
                        //r += (rgb[1] - rgb[0]) * rgbIllum2SpectGreen;

                        r.MAdd(ref SampledSpectrum.rgbIllum2SpectYellow, (rgb[0] - rgb[2]));
                        r.MAdd(ref SampledSpectrum.rgbIllum2SpectGreen, (rgb[1] - rgb[0]));
                    }
                    else
                    {
                        //r += (rgb[1] - rgb[2]) * rgbIllum2SpectYellow;
                        //r += (rgb[0] - rgb[1]) * rgbIllum2SpectRed;

                        r.MAdd(ref SampledSpectrum.rgbIllum2SpectYellow, (rgb[1] - rgb[2]));
                        r.MAdd(ref SampledSpectrum.rgbIllum2SpectRed, (rgb[0] - rgb[1]));
                    }
                }
                r *= .86445f;
            }
            r.ClampSelf();
            return r;
        }


        public static SampledSpectrum SSEFromRgb(float[] rgb, SpectrumType type = SpectrumType.Reflectance)
        {
            var r = new SampledSpectrum(0f);
            if (type == SpectrumType.Reflectance)
            {
                // Convert reflectance spectrum to RGB
                if (rgb[0] <= rgb[1] && rgb[0] <= rgb[2])
                {
                    // Compute reflectance _SampledSpectrum_ with _rgb[0]_ as minimum
                    //r += rgb[0] * rgbRefl2SpectWhite;
                    SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectWhite, rgb[0], ref r);

                    //SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectWhite, rgb[0]);
                    if (rgb[1] <= rgb[2])
                    {
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectCyan, (rgb[1] - rgb[0]), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectBlue, (rgb[2] - rgb[1]), ref r);
                        //r += (rgb[1] - rgb[0]) * rgbRefl2SpectCyan;
                        //r += (rgb[2] - rgb[1]) * rgbRefl2SpectBlue;
                    }
                    else
                    {
                        //r += (rgb[2] - rgb[0]) * rgbRefl2SpectCyan;
                        //r += (rgb[1] - rgb[2]) * rgbRefl2SpectGreen;

                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectCyan, (rgb[2] - rgb[0]), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectGreen, (rgb[1] - rgb[2]), ref r);
                    }
                }
                else if (rgb[1] <= rgb[0] && rgb[1] <= rgb[2])
                {
                    // Compute reflectance _SampledSpectrum_ with _rgb[1]_ as minimum
                    //r += rgb[1] * rgbRefl2SpectWhite;
                    SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectWhite, rgb[1], ref r);

                    if (rgb[0] <= rgb[2])
                    {
                        //r += (rgb[0] - rgb[1]) * rgbRefl2SpectMagenta;
                        //r += (rgb[2] - rgb[0]) * rgbRefl2SpectBlue;

                        SSE.MAddSSE(ref  SampledSpectrum.rgbRefl2SpectMagenta, (rgb[0] - rgb[1]), ref r);
                        SSE.MAddSSE(ref  SampledSpectrum.rgbRefl2SpectBlue, (rgb[2] - rgb[0]), ref r);
                    }
                    else
                    {
                        //r += (rgb[2] - rgb[1]) * rgbRefl2SpectMagenta;
                        //r += (rgb[0] - rgb[2]) * rgbRefl2SpectRed;
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectMagenta, (rgb[2] - rgb[1]), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectRed, (rgb[0] - rgb[2]), ref r);
                    }
                }
                else
                {
                    // Compute reflectance _SampledSpectrum_ with _rgb[2]_ as minimum
                    //r += rgb[2] * rgbRefl2SpectWhite;
                    SSE.MAddSSE(ref  SampledSpectrum.rgbRefl2SpectWhite, rgb[2], ref r);

                    if (rgb[0] <= rgb[1])
                    {
                        //r += (rgb[0] - rgb[2]) * rgbRefl2SpectYellow;
                        //r += (rgb[1] - rgb[0]) * rgbRefl2SpectGreen;
                        SSE.MAddSSE(ref  SampledSpectrum.rgbRefl2SpectYellow, (rgb[0] - rgb[2]), ref r);
                        SSE.MAddSSE(ref  SampledSpectrum.rgbRefl2SpectGreen, (rgb[1] - rgb[0]), ref r);
                    }
                    else
                    {
                        //r += (rgb[1] - rgb[2]) * rgbRefl2SpectYellow;
                        //r += (rgb[0] - rgb[1]) * rgbRefl2SpectRed;

                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectYellow, (rgb[1] - rgb[2]), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectRed, (rgb[0] - rgb[1]), ref r);
                    }
                }
                SSE.MulSSE(ref r, .94f, ref r);

                //r *= .94f;
            }
            else
            {
                // Convert illuminant spectrum to RGB
                if (rgb[0] <= rgb[1] && rgb[0] <= rgb[2])
                {
                    // Compute illuminant _SampledSpectrum_ with _rgb[0]_ as minimum
                    //r += rgb[0] * rgbIllum2SpectWhite;
                    SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectWhite, rgb[0], ref r);
                    if (rgb[1] <= rgb[2])
                    {
                        //r += (rgb[1] - rgb[0]) * rgbIllum2SpectCyan;
                        //r += (rgb[2] - rgb[1]) * rgbIllum2SpectBlue;
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectCyan, (rgb[1] - rgb[0]), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectBlue, (rgb[2] - rgb[1]), ref r);

                    }
                    else
                    {
                        // r += (rgb[2] - rgb[0]) * rgbIllum2SpectCyan;
                        //r += (rgb[1] - rgb[2]) * rgbIllum2SpectGreen;

                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectCyan, (rgb[2] - rgb[0]), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectGreen, (rgb[1] - rgb[2]), ref r);
                    }
                }
                else if (rgb[1] <= rgb[0] && rgb[1] <= rgb[2])
                {
                    // Compute illuminant _SampledSpectrum_ with _rgb[1]_ as minimum
                    //r += rgb[1] * rgbIllum2SpectWhite;
                    SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectWhite, rgb[1], ref r);

                    if (rgb[0] <= rgb[2])
                    {
                        //r += (rgb[0] - rgb[1]) * rgbIllum2SpectMagenta;
                        //r += (rgb[2] - rgb[0]) * rgbIllum2SpectBlue;

                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectMagenta, (rgb[0] - rgb[1]), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectBlue, (rgb[2] - rgb[0]), ref r);
                    }
                    else
                    {
                        //r += (rgb[2] - rgb[1]) * rgbIllum2SpectMagenta;
                        //r += (rgb[0] - rgb[2]) * rgbIllum2SpectRed;

                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectMagenta, (rgb[2] - rgb[1]), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectRed, (rgb[0] - rgb[2]), ref r);
                    }
                }
                else
                {
                    // Compute illuminant _SampledSpectrum_ with _rgb[2]_ as minimum
                    //r += rgb[2] * rgbIllum2SpectWhite;
                    SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectWhite, rgb[2], ref r);

                    if (rgb[0] <= rgb[1])
                    {
                        //r += (rgb[0] - rgb[2]) * rgbIllum2SpectYellow;
                        //r += (rgb[1] - rgb[0]) * rgbIllum2SpectGreen;

                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectYellow, (rgb[0] - rgb[2]), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectGreen, (rgb[1] - rgb[0]), ref r);
                    }
                    else
                    {
                        //r += (rgb[1] - rgb[2]) * rgbIllum2SpectYellow;
                        //r += (rgb[0] - rgb[1]) * rgbIllum2SpectRed;

                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectYellow, (rgb[1] - rgb[2]), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectRed, (rgb[0] - rgb[1]), ref r);
                    }
                }
                SSE.MulSSE(ref r, .86445f, ref r);
                //r *= .86445f;
            }
            //SSE.ClampSSE(ref r, ref r);
            //r.ClampSelf();
            return r;
        }

        public static SampledSpectrum SSEFromRgb(ref RgbSpectrum rgb, SpectrumType type = SpectrumType.Reflectance)
        {
            var r = new SampledSpectrum(0f);
            if (type == SpectrumType.Reflectance)
            {
                // Convert reflectance spectrum to RGB
                if (rgb[0] <= rgb[1] && rgb[0] <= rgb[2])
                {
                    // Compute reflectance _SampledSpectrum_ with _rgb[0]_ as minimum
                    //r += rgb[0] * rgbRefl2SpectWhite;
                    SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectWhite, rgb[0], ref r);

                    //SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectWhite, rgb[0]);
                    if (rgb[1] <= rgb[2])
                    {
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectCyan, (rgb[1] - rgb[0]), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectBlue, (rgb[2] - rgb[1]), ref r);
                        //r += (rgb[1] - rgb[0]) * rgbRefl2SpectCyan;
                        //r += (rgb[2] - rgb[1]) * rgbRefl2SpectBlue;
                    }
                    else
                    {
                        //r += (rgb[2] - rgb[0]) * rgbRefl2SpectCyan;
                        //r += (rgb[1] - rgb[2]) * rgbRefl2SpectGreen;

                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectCyan, (rgb[2] - rgb[0]), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectGreen, (rgb[1] - rgb[2]), ref r);
                    }
                }
                else if (rgb[1] <= rgb[0] && rgb[1] <= rgb[2])
                {
                    // Compute reflectance _SampledSpectrum_ with _rgb[1]_ as minimum
                    //r += rgb[1] * rgbRefl2SpectWhite;
                    SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectWhite, rgb[1], ref r);

                    if (rgb[0] <= rgb[2])
                    {
                        //r += (rgb[0] - rgb[1]) * rgbRefl2SpectMagenta;
                        //r += (rgb[2] - rgb[0]) * rgbRefl2SpectBlue;

                        SSE.MAddSSE(ref  SampledSpectrum.rgbRefl2SpectMagenta, (rgb[0] - rgb[1]), ref r);
                        SSE.MAddSSE(ref  SampledSpectrum.rgbRefl2SpectBlue, (rgb[2] - rgb[0]), ref r);
                    }
                    else
                    {
                        //r += (rgb[2] - rgb[1]) * rgbRefl2SpectMagenta;
                        //r += (rgb[0] - rgb[2]) * rgbRefl2SpectRed;
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectMagenta, (rgb[2] - rgb[1]), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectRed, (rgb[0] - rgb[2]), ref r);
                    }
                }
                else
                {
                    // Compute reflectance _SampledSpectrum_ with _rgb[2]_ as minimum
                    //r += rgb[2] * rgbRefl2SpectWhite;
                    SSE.MAddSSE(ref  SampledSpectrum.rgbRefl2SpectWhite, rgb[2], ref r);

                    if (rgb[0] <= rgb[1])
                    {
                        //r += (rgb[0] - rgb[2]) * rgbRefl2SpectYellow;
                        //r += (rgb[1] - rgb[0]) * rgbRefl2SpectGreen;
                        SSE.MAddSSE(ref  SampledSpectrum.rgbRefl2SpectYellow, (rgb[0] - rgb[2]), ref r);
                        SSE.MAddSSE(ref  SampledSpectrum.rgbRefl2SpectGreen, (rgb[1] - rgb[0]), ref r);
                    }
                    else
                    {
                        //r += (rgb[1] - rgb[2]) * rgbRefl2SpectYellow;
                        //r += (rgb[0] - rgb[1]) * rgbRefl2SpectRed;

                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectYellow, (rgb[1] - rgb[2]), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectRed, (rgb[0] - rgb[1]), ref r);
                    }
                }
                SSE.MulSSE(ref r, .94f, ref r);

                //r *= .94f;
            }
            else
            {
                // Convert illuminant spectrum to RGB
                if (rgb[0] <= rgb[1] && rgb[0] <= rgb[2])
                {
                    // Compute illuminant _SampledSpectrum_ with _rgb[0]_ as minimum
                    //r += rgb[0] * rgbIllum2SpectWhite;
                    SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectWhite, rgb[0], ref r);
                    if (rgb[1] <= rgb[2])
                    {
                        //r += (rgb[1] - rgb[0]) * rgbIllum2SpectCyan;
                        //r += (rgb[2] - rgb[1]) * rgbIllum2SpectBlue;
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectCyan, (rgb[1] - rgb[0]), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectBlue, (rgb[2] - rgb[1]), ref r);

                    }
                    else
                    {
                        // r += (rgb[2] - rgb[0]) * rgbIllum2SpectCyan;
                        //r += (rgb[1] - rgb[2]) * rgbIllum2SpectGreen;

                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectCyan, (rgb[2] - rgb[0]), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectGreen, (rgb[1] - rgb[2]), ref r);
                    }
                }
                else if (rgb[1] <= rgb[0] && rgb[1] <= rgb[2])
                {
                    // Compute illuminant _SampledSpectrum_ with _rgb[1]_ as minimum
                    //r += rgb[1] * rgbIllum2SpectWhite;
                    SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectWhite, rgb[1], ref r);

                    if (rgb[0] <= rgb[2])
                    {
                        //r += (rgb[0] - rgb[1]) * rgbIllum2SpectMagenta;
                        //r += (rgb[2] - rgb[0]) * rgbIllum2SpectBlue;

                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectMagenta, (rgb[0] - rgb[1]), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectBlue, (rgb[2] - rgb[0]), ref r);
                    }
                    else
                    {
                        //r += (rgb[2] - rgb[1]) * rgbIllum2SpectMagenta;
                        //r += (rgb[0] - rgb[2]) * rgbIllum2SpectRed;

                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectMagenta, (rgb[2] - rgb[1]), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectRed, (rgb[0] - rgb[2]), ref r);
                    }
                }
                else
                {
                    // Compute illuminant _SampledSpectrum_ with _rgb[2]_ as minimum
                    //r += rgb[2] * rgbIllum2SpectWhite;
                    SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectWhite, rgb[2], ref r);

                    if (rgb[0] <= rgb[1])
                    {
                        //r += (rgb[0] - rgb[2]) * rgbIllum2SpectYellow;
                        //r += (rgb[1] - rgb[0]) * rgbIllum2SpectGreen;

                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectYellow, (rgb[0] - rgb[2]), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectGreen, (rgb[1] - rgb[0]), ref r);
                    }
                    else
                    {
                        //r += (rgb[1] - rgb[2]) * rgbIllum2SpectYellow;
                        //r += (rgb[0] - rgb[1]) * rgbIllum2SpectRed;

                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectYellow, (rgb[1] - rgb[2]), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectRed, (rgb[0] - rgb[1]), ref r);
                    }
                }
                SSE.MulSSE(ref r, .86445f, ref r);
                //r *= .86445f;
            }
            //SSE.ClampSSE(ref r, ref r);
            //r.ClampSelf();
            return r;
        }

        public static SampledSpectrum AVXFromRgb(float[] rgb, SpectrumType type = SpectrumType.Reflectance)
        {
            var r = new SampledSpectrum(0f);
            if (type == SpectrumType.Reflectance)
            {
                // Convert reflectance spectrum to RGB
                if (rgb[0] <= rgb[1] && rgb[0] <= rgb[2])
                {
                    // Compute reflectance _SampledSpectrum_ with _rgb[0]_ as minimum
                    //r += rgb[0] * rgbRefl2SpectWhite;
                    AVX.MAdd(ref SampledSpectrum.rgbRefl2SpectWhite, rgb[0], ref r);

                    //SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectWhite, rgb[0]);
                    if (rgb[1] <= rgb[2])
                    {
                        AVX.MAdd(ref SampledSpectrum.rgbRefl2SpectCyan, (rgb[1] - rgb[0]), ref r);
                        AVX.MAdd(ref SampledSpectrum.rgbRefl2SpectBlue, (rgb[2] - rgb[1]), ref r);
                        //r += (rgb[1] - rgb[0]) * rgbRefl2SpectCyan;
                        //r += (rgb[2] - rgb[1]) * rgbRefl2SpectBlue;
                    }
                    else
                    {
                        //r += (rgb[2] - rgb[0]) * rgbRefl2SpectCyan;
                        //r += (rgb[1] - rgb[2]) * rgbRefl2SpectGreen;

                        AVX.MAdd(ref SampledSpectrum.rgbRefl2SpectCyan, (rgb[2] - rgb[0]), ref r);
                        AVX.MAdd(ref SampledSpectrum.rgbRefl2SpectGreen, (rgb[1] - rgb[2]), ref r);
                    }
                }
                else if (rgb[1] <= rgb[0] && rgb[1] <= rgb[2])
                {
                    // Compute reflectance _SampledSpectrum_ with _rgb[1]_ as minimum
                    //r += rgb[1] * rgbRefl2SpectWhite;
                    AVX.MAdd(ref SampledSpectrum.rgbRefl2SpectWhite, rgb[1], ref r);

                    if (rgb[0] <= rgb[2])
                    {
                        //r += (rgb[0] - rgb[1]) * rgbRefl2SpectMagenta;
                        //r += (rgb[2] - rgb[0]) * rgbRefl2SpectBlue;

                        AVX.MAdd(ref  SampledSpectrum.rgbRefl2SpectMagenta, (rgb[0] - rgb[1]), ref r);
                        AVX.MAdd(ref  SampledSpectrum.rgbRefl2SpectBlue, (rgb[2] - rgb[0]), ref r);
                    }
                    else
                    {
                        //r += (rgb[2] - rgb[1]) * rgbRefl2SpectMagenta;
                        //r += (rgb[0] - rgb[2]) * rgbRefl2SpectRed;
                        AVX.MAdd(ref SampledSpectrum.rgbRefl2SpectMagenta, (rgb[2] - rgb[1]), ref r);
                        AVX.MAdd(ref SampledSpectrum.rgbRefl2SpectRed, (rgb[0] - rgb[2]), ref r);
                    }
                }
                else
                {
                    // Compute reflectance _SampledSpectrum_ with _rgb[2]_ as minimum
                    //r += rgb[2] * rgbRefl2SpectWhite;
                    AVX.MAdd(ref  SampledSpectrum.rgbRefl2SpectWhite, rgb[2], ref r);

                    if (rgb[0] <= rgb[1])
                    {
                        //r += (rgb[0] - rgb[2]) * rgbRefl2SpectYellow;
                        //r += (rgb[1] - rgb[0]) * rgbRefl2SpectGreen;
                        AVX.MAdd(ref  SampledSpectrum.rgbRefl2SpectYellow, (rgb[0] - rgb[2]), ref r);
                        AVX.MAdd(ref  SampledSpectrum.rgbRefl2SpectGreen, (rgb[1] - rgb[0]), ref r);
                    }
                    else
                    {
                        //r += (rgb[1] - rgb[2]) * rgbRefl2SpectYellow;
                        //r += (rgb[0] - rgb[1]) * rgbRefl2SpectRed;

                        AVX.MAdd(ref SampledSpectrum.rgbRefl2SpectYellow, (rgb[1] - rgb[2]), ref r);
                        AVX.MAdd(ref SampledSpectrum.rgbRefl2SpectRed, (rgb[0] - rgb[1]), ref r);
                    }
                }
                AVX.Mul(ref r, .94f, ref r);

                //r *= .94f;
            }
            else
            {
                // Convert illuminant spectrum to RGB
                if (rgb[0] <= rgb[1] && rgb[0] <= rgb[2])
                {
                    // Compute illuminant _SampledSpectrum_ with _rgb[0]_ as minimum
                    //r += rgb[0] * rgbIllum2SpectWhite;
                    AVX.MAdd(ref SampledSpectrum.rgbIllum2SpectWhite, rgb[0], ref r);
                    if (rgb[1] <= rgb[2])
                    {
                        //r += (rgb[1] - rgb[0]) * rgbIllum2SpectCyan;
                        //r += (rgb[2] - rgb[1]) * rgbIllum2SpectBlue;
                        AVX.MAdd(ref SampledSpectrum.rgbIllum2SpectCyan, (rgb[1] - rgb[0]), ref r);
                        AVX.MAdd(ref SampledSpectrum.rgbIllum2SpectBlue, (rgb[2] - rgb[1]), ref r);

                    }
                    else
                    {
                        // r += (rgb[2] - rgb[0]) * rgbIllum2SpectCyan;
                        //r += (rgb[1] - rgb[2]) * rgbIllum2SpectGreen;

                        AVX.MAdd(ref SampledSpectrum.rgbIllum2SpectCyan, (rgb[2] - rgb[0]), ref r);
                        AVX.MAdd(ref SampledSpectrum.rgbIllum2SpectGreen, (rgb[1] - rgb[2]), ref r);
                    }
                }
                else if (rgb[1] <= rgb[0] && rgb[1] <= rgb[2])
                {
                    // Compute illuminant _SampledSpectrum_ with _rgb[1]_ as minimum
                    //r += rgb[1] * rgbIllum2SpectWhite;
                    AVX.MAdd(ref SampledSpectrum.rgbIllum2SpectWhite, rgb[1], ref r);

                    if (rgb[0] <= rgb[2])
                    {
                        //r += (rgb[0] - rgb[1]) * rgbIllum2SpectMagenta;
                        //r += (rgb[2] - rgb[0]) * rgbIllum2SpectBlue;

                        AVX.MAdd(ref SampledSpectrum.rgbIllum2SpectMagenta, (rgb[0] - rgb[1]), ref r);
                        AVX.MAdd(ref SampledSpectrum.rgbIllum2SpectBlue, (rgb[2] - rgb[0]), ref r);
                    }
                    else
                    {
                        //r += (rgb[2] - rgb[1]) * rgbIllum2SpectMagenta;
                        //r += (rgb[0] - rgb[2]) * rgbIllum2SpectRed;

                        AVX.MAdd(ref SampledSpectrum.rgbIllum2SpectMagenta, (rgb[2] - rgb[1]), ref r);
                        AVX.MAdd(ref SampledSpectrum.rgbIllum2SpectRed, (rgb[0] - rgb[2]), ref r);
                    }
                }
                else
                {
                    // Compute illuminant _SampledSpectrum_ with _rgb[2]_ as minimum
                    //r += rgb[2] * rgbIllum2SpectWhite;
                    AVX.MAdd(ref SampledSpectrum.rgbIllum2SpectWhite, rgb[2], ref r);

                    if (rgb[0] <= rgb[1])
                    {
                        //r += (rgb[0] - rgb[2]) * rgbIllum2SpectYellow;
                        //r += (rgb[1] - rgb[0]) * rgbIllum2SpectGreen;

                        AVX.MAdd(ref SampledSpectrum.rgbIllum2SpectYellow, (rgb[0] - rgb[2]), ref r);
                        AVX.MAdd(ref SampledSpectrum.rgbIllum2SpectGreen, (rgb[1] - rgb[0]), ref r);
                    }
                    else
                    {
                        //r += (rgb[1] - rgb[2]) * rgbIllum2SpectYellow;
                        //r += (rgb[0] - rgb[1]) * rgbIllum2SpectRed;

                        AVX.MAdd(ref SampledSpectrum.rgbIllum2SpectYellow, (rgb[1] - rgb[2]), ref r);
                        AVX.MAdd(ref SampledSpectrum.rgbIllum2SpectRed, (rgb[0] - rgb[1]), ref r);
                    }
                }
                AVX.Mul(ref r, .86445f, ref r);
                //r *= .86445f;
            }
            //AVX.Clamp(ref r, ref r);
            //r.ClampSelf();
            return r;
        }

        public static SampledSpectrum FromRgb(ref RgbSpectrum rgb, SpectrumType type = SpectrumType.Reflectance)
        {
            var r = new SampledSpectrum(0f);
            if (type == SpectrumType.Reflectance)
            {
                // Convert reflectance spectrum to RGB
                if (rgb.c1 <= rgb.c2 && rgb.c1 <= rgb.c3)
                {
                    // Compute reflectance _SampledSpectrum_ with _rgb.c1_ as minimum
                    //r += rgb.c1 * rgbRefl2SpectWhite;
                    SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectWhite, rgb.c1, ref r);

                    //SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectWhite, rgb.c1);
                    if (rgb.c2 <= rgb.c3)
                    {
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectCyan, (rgb.c2 - rgb.c1), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectBlue, (rgb.c3 - rgb.c2), ref r);
                        //r += (rgb.c2 - rgb.c1) * rgbRefl2SpectCyan;
                        //r += (rgb.c3 - rgb.c2) * rgbRefl2SpectBlue;
                    }
                    else
                    {
                        //r += (rgb.c3 - rgb.c1) * rgbRefl2SpectCyan;
                        //r += (rgb.c2 - rgb.c3) * rgbRefl2SpectGreen;

                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectCyan, (rgb.c3 - rgb.c1), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectGreen, (rgb.c2 - rgb.c3), ref r);
                    }
                }
                else if (rgb.c2 <= rgb.c1 && rgb.c2 <= rgb.c3)
                {
                    // Compute reflectance _SampledSpectrum_ with _rgb.c2_ as minimum
                    //r += rgb.c2 * rgbRefl2SpectWhite;
                    SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectWhite, rgb.c2, ref r);

                    if (rgb.c1 <= rgb.c3)
                    {
                        //r += (rgb.c1 - rgb.c2) * rgbRefl2SpectMagenta;
                        //r += (rgb.c3 - rgb.c1) * rgbRefl2SpectBlue;

                        SSE.MAddSSE(ref  SampledSpectrum.rgbRefl2SpectMagenta, (rgb.c1 - rgb.c2), ref r);
                        SSE.MAddSSE(ref  SampledSpectrum.rgbRefl2SpectBlue, (rgb.c3 - rgb.c1), ref r);
                    }
                    else
                    {
                        //r += (rgb.c3 - rgb.c2) * rgbRefl2SpectMagenta;
                        //r += (rgb.c1 - rgb.c3) * rgbRefl2SpectRed;
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectMagenta, (rgb.c3 - rgb.c2), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectRed, (rgb.c1 - rgb.c3), ref r);
                    }
                }
                else
                {
                    // Compute reflectance _SampledSpectrum_ with _rgb.c3_ as minimum
                    //r += rgb.c3 * rgbRefl2SpectWhite;
                    SSE.MAddSSE(ref  SampledSpectrum.rgbRefl2SpectWhite, rgb.c3, ref r);

                    if (rgb.c1 <= rgb.c2)
                    {
                        //r += (rgb.c1 - rgb.c3) * rgbRefl2SpectYellow;
                        //r += (rgb.c2 - rgb.c1) * rgbRefl2SpectGreen;
                        SSE.MAddSSE(ref  SampledSpectrum.rgbRefl2SpectYellow, (rgb.c1 - rgb.c3), ref r);
                        SSE.MAddSSE(ref  SampledSpectrum.rgbRefl2SpectGreen, (rgb.c2 - rgb.c1), ref r);
                    }
                    else
                    {
                        //r += (rgb.c2 - rgb.c3) * rgbRefl2SpectYellow;
                        //r += (rgb.c1 - rgb.c2) * rgbRefl2SpectRed;

                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectYellow, (rgb.c2 - rgb.c3), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectRed, (rgb.c1 - rgb.c2), ref r);
                    }
                }
                SSE.MulSSE(ref r, .94f, ref r);

                //r *= .94f;
            }
            else
            {
                // Convert illuminant spectrum to RGB
                if (rgb.c1 <= rgb.c2 && rgb.c1 <= rgb.c3)
                {
                    // Compute illuminant _SampledSpectrum_ with _rgb.c1_ as minimum
                    //r += rgb.c1 * rgbIllum2SpectWhite;
                    SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectWhite, rgb.c1, ref r);
                    if (rgb.c2 <= rgb.c3)
                    {
                        //r += (rgb.c2 - rgb.c1) * rgbIllum2SpectCyan;
                        //r += (rgb.c3 - rgb.c2) * rgbIllum2SpectBlue;
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectCyan, (rgb.c2 - rgb.c1), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectBlue, (rgb.c3 - rgb.c2), ref r);

                    }
                    else
                    {
                        // r += (rgb.c3 - rgb.c1) * rgbIllum2SpectCyan;
                        //r += (rgb.c2 - rgb.c3) * rgbIllum2SpectGreen;

                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectCyan, (rgb.c3 - rgb.c1), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectGreen, (rgb.c2 - rgb.c3), ref r);
                    }
                }
                else if (rgb.c2 <= rgb.c1 && rgb.c2 <= rgb.c3)
                {
                    // Compute illuminant _SampledSpectrum_ with _rgb.c2_ as minimum
                    //r += rgb.c2 * rgbIllum2SpectWhite;
                    SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectWhite, rgb.c2, ref r);

                    if (rgb.c1 <= rgb.c3)
                    {
                        //r += (rgb.c1 - rgb.c2) * rgbIllum2SpectMagenta;
                        //r += (rgb.c3 - rgb.c1) * rgbIllum2SpectBlue;

                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectMagenta, (rgb.c1 - rgb.c2), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectBlue, (rgb.c3 - rgb.c1), ref r);
                    }
                    else
                    {
                        //r += (rgb.c3 - rgb.c2) * rgbIllum2SpectMagenta;
                        //r += (rgb.c1 - rgb.c3) * rgbIllum2SpectRed;

                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectMagenta, (rgb.c3 - rgb.c2), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectRed, (rgb.c1 - rgb.c3), ref r);
                    }
                }
                else
                {
                    // Compute illuminant _SampledSpectrum_ with _rgb.c3_ as minimum
                    //r += rgb.c3 * rgbIllum2SpectWhite;
                    SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectWhite, rgb.c3, ref r);

                    if (rgb.c1 <= rgb.c2)
                    {
                        //r += (rgb.c1 - rgb.c3) * rgbIllum2SpectYellow;
                        //r += (rgb.c2 - rgb.c1) * rgbIllum2SpectGreen;

                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectYellow, (rgb.c1 - rgb.c3), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectGreen, (rgb.c2 - rgb.c1), ref r);
                    }
                    else
                    {
                        //r += (rgb.c2 - rgb.c3) * rgbIllum2SpectYellow;
                        //r += (rgb.c1 - rgb.c2) * rgbIllum2SpectRed;

                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectYellow, (rgb.c2 - rgb.c3), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectRed, (rgb.c1 - rgb.c2), ref r);
                    }
                }
                SSE.MulSSE(ref r, .86445f, ref r);
                //r *= .86445f;
            }
            //SSE.ClampSSE(ref r, ref r);
            //r.ClampSelf();
            return r;
        }

        public static SampledSpectrum FromRgb(RgbSpectrum rgb, SpectrumType type = SpectrumType.Reflectance)
        {
            return FromRgb(ref rgb, type);
        }

        public static SampledSpectrum FromRgb(RgbSpectrumInfo rgb, SpectrumType type = SpectrumType.Reflectance)
        {
            return FromRgb(ref rgb, type);
        }

        public static SampledSpectrum FromRgb(ref RgbSpectrumInfo rgb, SpectrumType type = SpectrumType.Reflectance)
        {
            var r = new SampledSpectrum(0f);
            if (type == SpectrumType.Reflectance)
            {
                // Convert reflectance spectrum to RGB
                if (rgb.c1 <= rgb.c2 && rgb.c1 <= rgb.c3)
                {
                    // Compute reflectance _SampledSpectrum_ with _rgb.c1_ as minimum
                    //r += rgb.c1 * rgbRefl2SpectWhite;
                    SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectWhite, rgb.c1, ref r);

                    //SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectWhite, rgb.c1);
                    if (rgb.c2 <= rgb.c3)
                    {
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectCyan, (rgb.c2 - rgb.c1), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectBlue, (rgb.c3 - rgb.c2), ref r);
                        //r += (rgb.c2 - rgb.c1) * rgbRefl2SpectCyan;
                        //r += (rgb.c3 - rgb.c2) * rgbRefl2SpectBlue;
                    }
                    else
                    {
                        //r += (rgb.c3 - rgb.c1) * rgbRefl2SpectCyan;
                        //r += (rgb.c2 - rgb.c3) * rgbRefl2SpectGreen;

                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectCyan, (rgb.c3 - rgb.c1), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectGreen, (rgb.c2 - rgb.c3), ref r);
                    }
                }
                else if (rgb.c2 <= rgb.c1 && rgb.c2 <= rgb.c3)
                {
                    // Compute reflectance _SampledSpectrum_ with _rgb.c2_ as minimum
                    //r += rgb.c2 * rgbRefl2SpectWhite;
                    SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectWhite, rgb.c2, ref r);

                    if (rgb.c1 <= rgb.c3)
                    {
                        //r += (rgb.c1 - rgb.c2) * rgbRefl2SpectMagenta;
                        //r += (rgb.c3 - rgb.c1) * rgbRefl2SpectBlue;

                        SSE.MAddSSE(ref  SampledSpectrum.rgbRefl2SpectMagenta, (rgb.c1 - rgb.c2), ref r);
                        SSE.MAddSSE(ref  SampledSpectrum.rgbRefl2SpectBlue, (rgb.c3 - rgb.c1), ref r);
                    }
                    else
                    {
                        //r += (rgb.c3 - rgb.c2) * rgbRefl2SpectMagenta;
                        //r += (rgb.c1 - rgb.c3) * rgbRefl2SpectRed;
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectMagenta, (rgb.c3 - rgb.c2), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectRed, (rgb.c1 - rgb.c3), ref r);
                    }
                }
                else
                {
                    // Compute reflectance _SampledSpectrum_ with _rgb.c3_ as minimum
                    //r += rgb.c3 * rgbRefl2SpectWhite;
                    SSE.MAddSSE(ref  SampledSpectrum.rgbRefl2SpectWhite, rgb.c3, ref r);

                    if (rgb.c1 <= rgb.c2)
                    {
                        //r += (rgb.c1 - rgb.c3) * rgbRefl2SpectYellow;
                        //r += (rgb.c2 - rgb.c1) * rgbRefl2SpectGreen;
                        SSE.MAddSSE(ref  SampledSpectrum.rgbRefl2SpectYellow, (rgb.c1 - rgb.c3), ref r);
                        SSE.MAddSSE(ref  SampledSpectrum.rgbRefl2SpectGreen, (rgb.c2 - rgb.c1), ref r);
                    }
                    else
                    {
                        //r += (rgb.c2 - rgb.c3) * rgbRefl2SpectYellow;
                        //r += (rgb.c1 - rgb.c2) * rgbRefl2SpectRed;

                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectYellow, (rgb.c2 - rgb.c3), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbRefl2SpectRed, (rgb.c1 - rgb.c2), ref r);
                    }
                }
                SSE.MulSSE(ref r, .94f, ref r);

                //r *= .94f;
            }
            else
            {
                // Convert illuminant spectrum to RGB
                if (rgb.c1 <= rgb.c2 && rgb.c1 <= rgb.c3)
                {
                    // Compute illuminant _SampledSpectrum_ with _rgb.c1_ as minimum
                    //r += rgb.c1 * rgbIllum2SpectWhite;
                    SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectWhite, rgb.c1, ref r);
                    if (rgb.c2 <= rgb.c3)
                    {
                        //r += (rgb.c2 - rgb.c1) * rgbIllum2SpectCyan;
                        //r += (rgb.c3 - rgb.c2) * rgbIllum2SpectBlue;
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectCyan, (rgb.c2 - rgb.c1), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectBlue, (rgb.c3 - rgb.c2), ref r);

                    }
                    else
                    {
                        // r += (rgb.c3 - rgb.c1) * rgbIllum2SpectCyan;
                        //r += (rgb.c2 - rgb.c3) * rgbIllum2SpectGreen;

                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectCyan, (rgb.c3 - rgb.c1), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectGreen, (rgb.c2 - rgb.c3), ref r);
                    }
                }
                else if (rgb.c2 <= rgb.c1 && rgb.c2 <= rgb.c3)
                {
                    // Compute illuminant _SampledSpectrum_ with _rgb.c2_ as minimum
                    //r += rgb.c2 * rgbIllum2SpectWhite;
                    SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectWhite, rgb.c2, ref r);

                    if (rgb.c1 <= rgb.c3)
                    {
                        //r += (rgb.c1 - rgb.c2) * rgbIllum2SpectMagenta;
                        //r += (rgb.c3 - rgb.c1) * rgbIllum2SpectBlue;

                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectMagenta, (rgb.c1 - rgb.c2), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectBlue, (rgb.c3 - rgb.c1), ref r);
                    }
                    else
                    {
                        //r += (rgb.c3 - rgb.c2) * rgbIllum2SpectMagenta;
                        //r += (rgb.c1 - rgb.c3) * rgbIllum2SpectRed;

                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectMagenta, (rgb.c3 - rgb.c2), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectRed, (rgb.c1 - rgb.c3), ref r);
                    }
                }
                else
                {
                    // Compute illuminant _SampledSpectrum_ with _rgb.c3_ as minimum
                    //r += rgb.c3 * rgbIllum2SpectWhite;
                    SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectWhite, rgb.c3, ref r);

                    if (rgb.c1 <= rgb.c2)
                    {
                        //r += (rgb.c1 - rgb.c3) * rgbIllum2SpectYellow;
                        //r += (rgb.c2 - rgb.c1) * rgbIllum2SpectGreen;

                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectYellow, (rgb.c1 - rgb.c3), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectGreen, (rgb.c2 - rgb.c1), ref r);
                    }
                    else
                    {
                        //r += (rgb.c2 - rgb.c3) * rgbIllum2SpectYellow;
                        //r += (rgb.c1 - rgb.c2) * rgbIllum2SpectRed;

                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectYellow, (rgb.c2 - rgb.c3), ref r);
                        SSE.MAddSSE(ref SampledSpectrum.rgbIllum2SpectRed, (rgb.c1 - rgb.c2), ref r);
                    }
                }
                SSE.MulSSE(ref r, .86445f, ref r);
                //r *= .86445f;
            }
            //SSE.ClampSSE(ref r, ref r);
            //r.ClampSelf();
            return r;
        }
        #region Spectral Distributions

        public static RegularSPD CreateRegularSpd(ref RgbSpectrum col, SpectrumType t)
        {
            float[] l, v;
            FromRgb(ref col, t).ToSpectra(out l, out v);
            return new RegularSPD(v, SampledSpectrum.sampledLambdaStart, SampledSpectrum.sampledLambdaEnd, SampledSpectrum.nSpectralSamples);
        }

        public static RegularSPD CreateRegularSpd(float r, float g, float b, SpectrumType t)
        {
            float[] l, v;
            FromRgb(new RgbSpectrum(r,g,b), t).ToSpectra(out l, out v);
            return new RegularSPD(v, SampledSpectrum.sampledLambdaStart, SampledSpectrum.sampledLambdaEnd, SampledSpectrum.nSpectralSamples);
        }

        public static RegularSPD CreateRegularSpd(ref RgbSpectrumInfo col, SpectrumType t)
        {
            float[] l, v;
            FromRgb(ref col, t).ToSpectra(out l, out v);
            return new RegularSPD(v, SampledSpectrum.sampledLambdaStart, SampledSpectrum.sampledLambdaEnd, SampledSpectrum.nSpectralSamples);
        }
        public static RegularSPD CreateRegularSpd(ref SampledSpectrum spd)
        {
            float[] l, v;
            spd.ToSpectra(out l, out v);
            return new RegularSPD(v, SampledSpectrum.sampledLambdaStart, SampledSpectrum.sampledLambdaEnd, SampledSpectrum.nSpectralSamples);
        }
        public static RegularSPD CreateRegularSpd(float[] spd)
        {
            return new RegularSPD(spd, SampledSpectrum.CIEstart, SampledSpectrum.CIEend, spd.Length);
        }


        public static RegularSPD CreateRegular(float[] wl)
        {
            var nSamples = wl.Length / 2;
            var lambda = new float[nSamples];
            var val = new float[nSamples];

            for (int index = 0; index < lambda.Length; index++)
            {
                lambda[index] = wl[index * 2];
                val[index] = wl[index * 2 + 1];
            }

            var spd = new RegularSPD(val, SampledSpectrum.CIEstart, SampledSpectrum.CIEend, val.Length);
            return spd;
        }
        public static RegularSPD CreateRegularFromRegular(float[] wl)
        {
            var spd = new RegularSPD(wl, SampledSpectrum.CIEstart, SampledSpectrum.CIEend, wl.Length);
            return spd;
        }
        public static SampledSpectrum CreateSampled(float[] wl, bool refl = true)
        {

            var nSamples = wl.Length / 2;
            var lambda = new float[nSamples];
            var val = new float[nSamples];

            for (int index = 0; index < lambda.Length; index++)
            {
                lambda[index] = wl[index * 2];
                val[index] = wl[index * 2 + 1];
            }

            return SampledSpectrum.FromSampled(lambda, val, refl ? SpectrumType.Reflectance : SpectrumType.Illuminant);
        }


        public static IrregularSPD CreateIrregular(float[] wl)
        {

            var nSamples = wl.Length / 2;
            var lambda = new float[nSamples];
            var val = new float[nSamples];

            for (int index = 0; index < lambda.Length; index++)
            {
                lambda[index] = wl[index * 2];
                val[index] = wl[index * 2 + 1];
            }

            var spd = new IrregularSPD(lambda, val, lambda.Length, 300f / lambda.Length);
            spd.Normalize();
            return spd;
        }
        public static IrregularSPD CreateIrregular(float[] wl, float[] samples)
        {

            var lambda = wl;
            var val = samples;

            var spd = new IrregularSPD(lambda, val, lambda.Length, 300f / lambda.Length);
            //spd.Normalize();
            return spd;
        }

        public static RgbSpectrum ToRgb(SpectralDistribution spd)
        {
            var c = new RgbSpectrum();
            float[] vc = new float[SampledSpectrum.nCIE];

            spd.Sample(SampledSpectrum.nCIE, SampledSpectrum.CIE_lambda, vc);
            for (var i = 0; i < SampledSpectrum.nCIE; ++i)
            {
                float v = spd.Sample(i + SampledSpectrum.CIEstart);
                vc[i] = v;
            }
            /*
            for (var i = 0; i < SampledSpectrum.nCIE; ++i)
            {
                float v = spd.Sample(i + SampledSpectrum.CIEstart);
                c.c1 += v * SampledSpectrum.CIE_X[i];
                c.c2 += v * SampledSpectrum.CIE_Y[i];
                c.c3 += v * SampledSpectrum.CIE_Z[i];
            }*/
            c = new RgbSpectrum(
            SSE.VectorDot(vc, SampledSpectrum.CIE_X, 468),
            SSE.VectorDot(vc, SampledSpectrum.CIE_Y, 468),
            SSE.VectorDot(vc, SampledSpectrum.CIE_Z, 468));

            var xyz = (c / 683f);

            float[] rgb;
            SampledSpectrum.XYZToRGB(xyz.ToArray(), out rgb);
            c = new RgbSpectrum(rgb);
            //res.GammaCorrection();
            return c;
        }

        #endregion
    }
}